#include "hw_ints.h"
#include "hw_memmap.h"
#include "hw_types.h"
#include "debug.h"
#include "gpio.h"
#include "sysctl.h"
#include "lcd.h"

#define LCD_CS GPIO_PIN_0
#define LCD_RST GPIO_PIN_1
#define LCD_CLK GPIO_PIN_2
#define LCD_DATA GPIO_PIN_5


void waitms(int a){
 long int i;
 long int j;
 j=1000*a;
 for (i=0;i<j;i++){ ; }
}

#define CS0 GPIOPinWrite(GPIO_PORTA_BASE, LCD_CS, 0x00);
#define CS1 GPIOPinWrite(GPIO_PORTA_BASE, LCD_CS, 0xFF);
#define RESET0 GPIOPinWrite(GPIO_PORTA_BASE, LCD_RST, 0x00);
#define RESET1 GPIOPinWrite(GPIO_PORTA_BASE, LCD_RST, 0xFF);
#define CLK0 GPIOPinWrite(GPIO_PORTA_BASE, LCD_CLK, 0x00);
#define CLK1 GPIOPinWrite(GPIO_PORTA_BASE, LCD_CLK, 0xFF);
#define SDA0 GPIOPinWrite(GPIO_PORTA_BASE, LCD_DATA, 0x00);
#define SDA1 GPIOPinWrite(GPIO_PORTA_BASE, LCD_DATA, 0xFF);

void shiftBits(byte b) {
  CLK0
  if ((b&128)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&64)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&32)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&16)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&8)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&4)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&2)!=0) SDA1 else SDA0
  CLK1

  CLK0
  if ((b&1)!=0) SDA1 else SDA0
  CLK1
}


//send data
void sendData(byte data) {

  CLK0
  SDA1                                                 //1 for param
  CLK1

  shiftBits(data);
}

//send cmd
void sendCMD(byte data) {

  CLK0
  SDA0                                                 //1 for cmd
  CLK1

  shiftBits(data);
}

#define LCMD_YCOORD 0x75
#define LCMD_XCOORD 0x15
#define LCMD_DATA 0x5C


void LCD_put_pixel(unsigned char color, unsigned char x, unsigned char y){
  x += 2;          // for some reason starts at 2
  sendCMD(LCMD_YCOORD);   // page start/end ram
  sendData(x);            
  sendData(132);          
  sendCMD(LCMD_XCOORD);   // column start/end ram
  sendData(y);  
  sendData(131); 
  sendCMD(LCMD_DATA);   // write data
  sendData(color); 
}

void LCD_hline (byte x0,byte x1,byte y,word color){
 int i;
 y+=2;
 sendCMD(LCMD_YCOORD);
 sendData(y);
 sendData(y);
 sendCMD(LCMD_XCOORD);
 sendData(x0);
 sendData(x1);
 sendCMD(LCMD_DATA);
 for (i=x0>>1;i<(x1>>1);i++) LCD_send2(color);
}

void LCD_vline (byte x,byte y0,byte y1,byte color){
 int i;
 y0+=2;
 y1+=2;
 sendCMD(LCMD_YCOORD);
 sendData(y0);
 sendData(y1);
 sendCMD(LCMD_XCOORD);
 sendData(x);
 sendData(x);
 sendCMD(LCMD_DATA);
 for (i=y0;i<y1;i++) sendData(color);
}

void LCD_send2(word color){
 	sendData((color & 0x0ff0)>>4);
	sendData(((color & 0x000f)<<4) | ((color & 0x0f00)>>4));
	sendData((color & 0x00ff));
}

void LCD_clear(word color){  
	int i;
	int c1,c2,c3;

	c1=(color & 0x0ff0)>>4;
	c2=((color & 0x000f)<<4) | ((color & 0x0f00)>>4);
	c3=(color & 0x00ff);

    sendCMD(0x75);   // page start/end ram
  	sendData(0);            // for some reason starts at 2
  	sendData(131);          
  
  	sendCMD(0x15);   // column start/end ram
  	sendData(0);          
  	sendData(131);


  	sendCMD(0x5c);    // write some stuff (background)
  	for (i = 0; i < 17424; i++){
	sendData(c1);
	sendData(c2);
	sendData(c3);
//    	sendData(color);
  	}
}


void LCD_init(void){
	int i;
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	GPIODirModeSet(GPIO_PORTA_BASE, LCD_CS, GPIO_DIR_MODE_OUT);
	GPIODirModeSet(GPIO_PORTA_BASE, LCD_RST, GPIO_DIR_MODE_OUT);
	GPIODirModeSet(GPIO_PORTA_BASE, LCD_CLK, GPIO_DIR_MODE_OUT);
	GPIODirModeSet(GPIO_PORTA_BASE, LCD_DATA, GPIO_DIR_MODE_OUT);

	CS0
  	SDA0
  	CLK1

  	RESET1
  	RESET0
  	RESET1

  	CLK1
  	SDA1
  	CLK1

  	waitms(10);

  	sendCMD(0xca);
  
  	//added
  	sendData(0x03);
  	sendData(32);
  	sendData(12);
  	sendData(0x00);
  
  	sendCMD(0xbb);  // common scan direction
  	sendData(0x01);

  	sendCMD(0xd1);  // oscillator on

  	sendCMD(0x94);  // sleep out

  	sendCMD(0x81);  // electronic volume, this is kinda contrast/brightness
  	sendData(5);//ff);       //  this might be different for individual LCDs
  	sendData(0x01);//01);     //

  	sendCMD(0x20);  // power ctrl
  	sendData(0x0f);      //everything on, no external reference resistors
  	waitms(100);

  	sendCMD(0xa7);  // display mode


  	sendCMD(0xbc);  // datctl
  	sendData(0x00);
  	sendData(0);
  	sendData(0x02); //0x01
  	sendData(0x00);
  
  	//3-3-2 palette
  	sendCMD(0xce);   // setup color lookup table
    // color table
    //RED
    sendData(0);
    sendData(2);
    sendData(4);
    sendData(6);
    sendData(8);
    sendData(10);
    sendData(12);
    sendData(15);
    // GREEN
    sendData(0);
    sendData(2);
    sendData(4);
    sendData(6);
    sendData(8);
    sendData(10);
    sendData(12);
    sendData(15);
    //BLUE
    sendData(0);
    sendData(4);
    sendData(9);
    sendData(15);
  

  	sendCMD(0x25);  // nop

	LCD_clear(0);

  	sendCMD(0xaf);   // display on

  	waitms(200);

 	for (i = 0; i < 150; i++){   // this loop adjusts the contrast, change the number of iterations to get
   		sendCMD(0xd6);                // desired contrast.  This might be different for individual LCDs
   		waitms(2);
 	}

}



